package com.zero.qth.service.impl;

import java.nio.charset.StandardCharsets;
import java.util.Date;
import java.util.List;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.zero.common.core.domain.result.AjaxResult;
import com.zero.qth.controller.req.PaymentRefundReq;
import com.zero.qth.domain.Driver;
import com.zero.qth.domain.DriverBalanceDetail;
import com.zero.qth.domain.Orders;
import com.zero.qth.enums.BalanceTypelEnum;
import com.zero.qth.enums.PaymentTypeEnum;
import com.zero.qth.mapper.DriverMapper;
import com.zero.qth.mapper.OrdersMapper;
import com.zero.qth.service.IDriverBalanceDetailService;
import com.zero.qth.vo.PaymentVo;
import com.zero.qth.weixin.config.WeixinPayConfig;
import com.zero.qth.weixin.pojo.Create;
import com.zero.qth.weixin.utils.AesUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import com.zero.qth.mapper.PaymentMapper;
import com.zero.qth.domain.Payment;
import com.zero.qth.service.IPaymentService;
import org.springframework.transaction.annotation.Transactional;


/**
 * 流水表Service业务层处理
 * 
 * @author cai-xu-kun
 * @date 2025-08-28
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class PaymentServiceImpl extends ServiceImpl<PaymentMapper, Payment> implements IPaymentService {

    private final PaymentMapper paymentMapper;
    private final OrdersMapper ordersMapper;
    private final DriverMapper driverMapper;

    private final IDriverBalanceDetailService driverBalanceDetailService;

    private final Create createRefund;
    private final WeixinPayConfig weixinPayConfig;


    /* 微信退款 */
    @Override
    public AjaxResult refund(PaymentRefundReq req) {
        // 查询流水表
        Payment payment = paymentMapper.selectOne(new LambdaQueryWrapper<Payment>().eq(Payment::getOrderId, req.getOrderId()));
        if (payment == null) {
            throw new RuntimeException("订单不存在");
        } else if (PaymentTypeEnum.OUT.getCode().equals(payment.getType())) {
            throw new RuntimeException("该订单已退款");
        }

        Create.CreateRequest createRefundRequest = new Create.CreateRequest();
        // 原支付订单信息
//        createRefundRequest.outTradeNo = req.getOrderId();
        createRefundRequest.transactionId = payment.getTransactionId();//改用交易ID
        createRefundRequest.amount = new Create.AmountReq();
        long amt = payment.getPayAmount();
        createRefundRequest.amount.total = amt;

        // 退款信息
        // 商户退款单号生成方式商户视实际情况生成，需要保证平台商户下全局唯一
        createRefundRequest.outRefundNo = "REFUND_" + req.getOrderId();
        createRefundRequest.reason = req.getReason();
        createRefundRequest.amount.refund = amt;
        createRefundRequest.amount.currency = "CNY";

        // 退款成功，退款关闭，退款异常时需要微信支付通知商户商户，可以加上回调URL，退款到这几个状态时会调用这个URL通知商户
        createRefundRequest.notifyUrl = weixinPayConfig.getRefundNotifyUrl();
//        createRefundRequest.notifyUrl = "http://11rh2448354cf.vicp.fun/notify/refundOrder";

        Create.Refund refund;
        try {
            refund = createRefund.run(createRefundRequest);
            System.err.println(JSON.toJSONString(refund));
        } catch (com.zero.qth.weixin.utils.WXPayUtility.ApiException e) {
            System.err.println(e.getMessage());
            // 申请退款处理异常处理逻辑
            switch (e.getErrorCode()) {
                case "SYSTEM_ERROR":
                    // 错误：系统错误
                    // 解决方式：稍后原单重试
                    // 描述：微信支付系统失败，一定要原单重试，系统失败直接立即重试大概率还会是系统失败，建议等1分钟后再重试
                    break;
                case "FREQUENCY_LIMITED":
                    // 错误：限频报错
                    // 解决方式：稍后原单重试
                    // 描述： 退款接口频率限制，一定要原单重试，直接立即重试大概率还会是系统失败，建议等1分钟后再重试
                    break;
                case "USER_ACCOUNT_ABNORMAL":
                    // 错误：用户账户异常
                    // 解决方式：退款受理失败，商户可以自行处理退款，也可以登录商户平台进入交易中心发起异常退款
                    // 描述：用户注销或者被管控了，这笔订单已经不能发起退款，这个错误就不需要重试了
                    break;
                case "NOT_ENOUGH":
                    // 错误：账户余额不足
                    // 解决方式：商户充值之后原单重试
                    // 描述：商户账户余额不足，导致退款失败，商户充值之后一定要原单重试
                    break;
                case "NO_AUTH":
                    // 错误：无退款权限
                    // 解决方式：检查商户是否是被处罚：登录商户平台进入账户中心-违约记录查询是否违约记录，如果有按照上面的指引解决违约记录之后原单重试
                    // 描述：商户被处罚
                    break;
                case "SIGN_ERROR":
                    // 错误：签名错误
                    // 解决方式：检查平台商户证书序列号，证书私钥文件，公钥ID，公钥文件，同时确认下签名过程是不是按照微信支付的签名方式
                    // 描述：签名报错，需要确认签名材料和签名流程是否正确
                    break;
                case "PARAM_ERROR":
                    // 错误：参数错误
                    // 解决方式：按照报错返回的message，重新输入请求参数
                    // 描述：参数的类型，长度，或者必填选项没有填写等
                    break;
                case "INVALID_REQUEST":
                    // 错误：请求非法，请求参数正确，但是不符合退款业务规则
                    // 解决方式：根据具体message查看具体哪里不符合业务规则，如果可以修改参数达到符合业务规则的修改请求符合业务规则之后再原单重试
                    // 描述：不符合业务规则的场景如：
                    // - 交易时间超过365天，不允许发起退款
                    // - 一笔订单退款次数已经超过50次了，这笔订单不允许发起新的退款
                    // - 申请退款的金额超过了这笔订单剩余可退金额，不允许申请退款
                    break;
                default:
                    // 其他类型错误：稍等一会后原单重试
                    break;
            }

        }
        return null;
    }

    /*微信退款回调*/
    @Override
    @Transactional(rollbackFor = Exception.class)
    public String weixinRefundNotify(JSONObject request) {
        JSONObject resource = request.getJSONObject("resource");
        // original_type、algorithm、ciphertext、associated_data、nonce 加密相关字段
        log.info("打印加密资源内部：{}", resource);

        // 获取微信支付「APIv3 密钥」
        String apiV3key = weixinPayConfig.getApiV3Key();
        byte[] key = apiV3key.getBytes(StandardCharsets.UTF_8);// 再转 UTF-8 字节数组
        AesUtil aesUtil = new AesUtil(key);
        // 提取「关联数据」并转字节，再转 UTF-8 字节数组
        String associatedDataStr = resource.getString("associated_data");
        byte[] associatedData = associatedDataStr.getBytes(StandardCharsets.UTF_8);
        // 提取随机数，再转 UTF-8 字节数组
        String nonceStr = resource.getString("nonce");
        byte[] nonce = nonceStr.getBytes(StandardCharsets.UTF_8);

        // 提取加密密文，再转 UTF-8 字节数组
        String ciphertext = resource.getString("ciphertext");

        try{
            String wxResult = aesUtil.decryptToString(associatedData, nonce ,ciphertext); // 执行 AES-GCM 解密
            JSONObject orderInfo = JSONObject.parse(wxResult);                            // 将解密结果转成JSON对象
            String outTradeNo  = orderInfo.getString("out_trade_no");                 //提取商户号订单
            String orderId = outTradeNo.split("_")[0];

            Payment payment = paymentMapper.selectOne(new LambdaQueryWrapper<Payment>().eq(Payment::getOrderId, orderId));
            if (payment == null) {
                throw new RuntimeException("参数异常");
            }

            this.refundWithDriver(payment);

            payment.setType(1);                 //更新 type 为 1
            payment.setRefundTime(new Date());  // 更新退款时间
            paymentMapper.updateById(payment);
            Orders order = new Orders();
            order.setId(orderId);
            order.setStatus(8);
            ordersMapper.updateById(order);

            log.info("订单[{}]退款成功", orderId);

            return "SUCCESS";

        } catch (Exception e) {
            log.error("解密失败");
            throw new RuntimeException(e);
        }
    }

    /*根据微信退款回调，更新driver表余额，DriverBalanceDetail*/
    private void refundWithDriver(Payment payment) {
        // (1)查询订单获取司机Id
        Orders orders = ordersMapper.selectOrdersById(payment.getOrderId());
        if (orders == null || orders.getDriverId() == null) {
            log.error("司机不存在");
            throw new RuntimeException("参数异常");
        }
        Long driverId = orders.getDriverId();
        String orderId = payment.getOrderId();

        // (2)查询司机信息
        Driver driver = driverMapper.selectById(driverId);

        // (3)获取退款金额，计算更新司机新余额
        Long refundAmount = orders.getPrice();
        Long currentBalance = driver.getAccountBalance() == null ? 0 :driver.getAccountBalance();
        Long newAccountBalance = currentBalance - refundAmount;
        if (newAccountBalance < 0) {
            log.error("司机[{}]余额不足，当前余额：{}。需要：{}", driverId, currentBalance, refundAmount);
        }
        driver.setAccountBalance(newAccountBalance);
        driverMapper.updateById(driver);

        // (4)记录余额明细
        DriverBalanceDetail balanceDetail = new DriverBalanceDetail();
        balanceDetail.setDriverId(driverId);
        balanceDetail.setOrderId(payment.getOrderId());
        balanceDetail.setAmount(refundAmount);
        balanceDetail.setBalanceType(BalanceTypelEnum.REFUND_OUTCOME.getCode());
        balanceDetail.setRemainingBalance(newAccountBalance);
        balanceDetail.setCreateTime(new Date());
        driverBalanceDetailService.save(balanceDetail);

        // (5)处理父司机的提成明细
        DriverBalanceDetail parentDetail = driverBalanceDetailService.getOne(
                new LambdaQueryWrapper<DriverBalanceDetail>()
                        .eq(DriverBalanceDetail::getOrderId, orderId)
                        .eq(DriverBalanceDetail::getChildId, driverId)
                        .eq(DriverBalanceDetail::getBalanceType, BalanceTypelEnum.CHILD_INCOME.getCode())
        );

        if (parentDetail != null) {
            Long parentDriverId = parentDetail.getDriverId();
            Long parentAmount = parentDetail.getAmount();

            if (parentDriverId == null || parentAmount == null || parentAmount <= 0) {
                log.error("关联信息不完整");
                return;
            }
            // 查司机表，父司机信息
            Driver parentDriver = driverMapper.selectById(parentDriverId);
            if(parentDriver == null) {
                log.error("父类司机已不存在");
                return;
            }
            // 计算父类新的余额
            Long parentOldBalance = parentDriver.getAccountBalance() == null ? 0 : parentDriver.getAccountBalance();
            Long parentNewBalance = parentOldBalance - parentAmount;

            // 更新进父类(司机表)余额
            parentDriver.setAccountBalance(parentNewBalance);
            driverMapper.updateById(parentDriver);

            // 再次记录父类抽成退款余额明细
            DriverBalanceDetail newParentDetail = new DriverBalanceDetail();
            BeanUtils.copyProperties(parentDetail, newParentDetail);
            newParentDetail.setId(null);
            newParentDetail.setBalanceType(BalanceTypelEnum.CHILD_OUTCOME.getCode());
            // 并且更新进数据库
            driverBalanceDetailService.save(newParentDetail);

            log.info("父类司机[{}]退款处理完成，订单ID:{}，扣除金额:{}", parentDriverId, orderId, parentAmount);
        } else {
            log.info("未查询到父类司机关联记录，orderId:{}，childDriverId:{}", orderId, driverId);
        }

    }

    /*========================================================================*/

    /**
     * 查询流水表分页
     *
     * @param payment 流水表
     * @param p       分页数据
     * @return 流水表
     */
    @Override
    public Page<PaymentVo> selectPaymentListPage(Payment payment, Page<Payment> p) {
        return paymentMapper.selectPaymentListPage(payment, p);
    }

    /**
     * 查询流水表
     *
     * @param id 流水表主键
     * @return 流水表
     */
    @Override
    public Payment selectPaymentById(Long id) {
        return paymentMapper.selectPaymentById(id);
    }


    /**
     * 查询流水表列表
     *
     * @param payment 流水表
     * @return 流水表
     */
    @Override
    public List<PaymentVo> selectPaymentList(Payment payment) {
        return paymentMapper.selectPaymentList(payment);
    }

    /**
     * 新增流水表
     *
     * @param payment 流水表
     * @return 结果
     */
    @Override
    public int insertPayment(Payment payment) {
        return paymentMapper.insertPayment(payment);
    }

    /**
     * 修改流水表
     *
     * @param payment 流水表
     * @return 结果
     */
    @Override
    public int updatePayment(Payment payment) {
        return paymentMapper.updatePayment(payment);
    }

    /**
     * 批量删除流水表
     *
     * @param ids 需要删除的流水表主键
     * @return 结果
     */
    @Override
    public int deletePaymentByIds(Long[] ids) {
        return paymentMapper.deletePaymentByIds(ids);
    }

    /**
     * 删除流水表信息
     *
     * @param id 流水表主键
     * @return 结果
     */
    @Override
    public int deletePaymentById(Long id) {
        return paymentMapper.deletePaymentById(id);
    }


    @Override
    public List<PaymentVo> selectPaymentVoByOrderId(String orderId) {
        Payment paymentQuery = new Payment();
        paymentQuery.setOrderId(orderId);
        return paymentMapper.selectPaymentList(paymentQuery);
    }



}
